package com.centanet.framework.network;

import android.support.v4.util.ArrayMap;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import com.centanet.framework.interfaces.ILoggerTag;
import com.centanet.framework.interfaces.IResponseListener;
import com.google.gson.Gson;
import com.orhanobut.logger.Logger;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.zip.GZIPInputStream;

/**
 * Gson数据请求
 */
public class GsonRequest<T> extends Request<T> {

    private static final Gson GSON = new Gson();
    private final com.centanet.framework.interfaces.IResponseListener<T> iResponseListener;
    private ArrayMap<String, String> headers;
    private byte[] params;
    private Class<T> aClass;
    private String bodyContentType;

    /**
     * @param builder {@link Builder}
     */
    public GsonRequest(Builder<T> builder) {
        this(builder.method, builder.url, builder.iResponseListener);
        this.headers = builder.headers;
        this.params = builder.params;
        this.aClass = builder.aClass;
        setTag(builder.tag);
        setRetryPolicy(builder.retryPolicy);
        setShouldCache(builder.shouldCache);
        bodyContentType = builder.bodyContentType;
    }

    private GsonRequest(int method, String url, final IResponseListener<T> iResponseListener) {
        super(method, url, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                iResponseListener.onErrorResponse(volleyError);
            }
        });
        this.iResponseListener = iResponseListener;
    }

    @Override
    public ArrayMap<String, String> getHeaders() {
        return headers;
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
        return params;
    }

    @Override
    public String getBodyContentType() {
        return bodyContentType;
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse networkResponse) {
        final byte[] h = new byte[2];
        h[0] = networkResponse.data[0];
        h[1] = networkResponse.data[1];
        final int headerData = (h[0] << 8) | h[1] & 0xFF;
        StringBuilder builder = new StringBuilder();
        if (headerData != -1 && headerData == 0x1f8b) {
            ByteArrayInputStream bis = new ByteArrayInputStream(networkResponse.data);
            try {
                InputStream in = new GZIPInputStream(bis);
                BufferedReader r = new BufferedReader(new InputStreamReader(in),
                        100);
                for (String line = r.readLine(); line != null; line = r.readLine()) {
                    builder.append(line);
                }
                in.close();
                bis.close();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            String parsed;
            try {
                parsed = new String(networkResponse.data, HttpHeaderParser.parseCharset(networkResponse.headers, "UTF-8"));
            } catch (UnsupportedEncodingException var4) {
                parsed = new String(networkResponse.data);
            }
            builder.append(parsed);
        }
        Logger.t(ILoggerTag.FRAME_RESPONSE).json(builder.toString());
        try {
            return Response.success(GSON.fromJson(builder.toString(), aClass), HttpHeaderParser.parseCacheHeaders(networkResponse));
        } catch (Exception e) {
            Logger.t(ILoggerTag.JSON_PARSE_ERROR).e(e, "Exception");
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T response) {
        iResponseListener.onResponse(response);
    }

    /**
     * 构建{@link GsonRequest}请求参数
     *
     * @param <T>
     */
    static class Builder<T> {

        private String url;
        private int method;
        private ArrayMap<String, String> headers;
        private byte[] params;
        private Class<T> aClass;
        private IResponseListener<T> iResponseListener;
        private Object tag;
        private RetryPolicy retryPolicy;
        private String bodyContentType;
        private boolean shouldCache = true;

        /**
         * @param aClass            目标实体
         * @param iResponseListener 响应监听
         */
        public Builder(Class<T> aClass, IResponseListener<T> iResponseListener) {
            this.aClass = aClass;
            this.iResponseListener = iResponseListener;
            this.retryPolicy = new DefaultRetryPolicy();
        }

        /**
         * url地址
         */
        public Builder<T> url(String url) {
            this.url = url;
            return this;
        }

        /**
         * 请求方式
         */
        public Builder<T> method(int method) {
            this.method = method;
            return this;
        }

        /**
         * 请求头
         */
        public Builder<T> headers(ArrayMap<String, String> headers) {
            this.headers = headers;
            return this;
        }

        /**
         * 请求参数
         */
        public Builder<T> params(byte[] params) {
            this.params = params;
            return this;
        }

        /**
         * 请求标签
         */
        public Builder<T> tag(Object tag) {
            this.tag = tag;
            return this;
        }

        /**
         * retryPolicy
         */
        public Builder<T> retryPolicy(RetryPolicy retryPolicy) {
            this.retryPolicy = retryPolicy;
            return this;
        }

        /**
         * the content type of the POST or PUT body.
         */
        public Builder<T> bodyContentType(String bodyContentType) {
            this.bodyContentType = bodyContentType;
            return this;
        }

        /**
         * 缓存 默认true
         */
        public Builder<T> shouldCache(boolean shouldCache) {
            this.shouldCache = shouldCache;
            return this;
        }

        /**
         * 构建
         *
         * @return {@link GsonRequest}
         */
        public GsonRequest<T> build() {
            return new GsonRequest<>(this);
        }
    }
}
